package com.xinqi.util.sqlsession;

import org.apache.ibatis.session.SqlSession;

import java.lang.reflect.ParameterizedType;
import java.util.concurrent.atomic.AtomicBoolean;
/*synchronized可重入锁的实现原理：

synchronized底层是利用计算机系统mutex Lock实现的。每一个可重入锁都会关联一个线程ID和一个锁状态status。

当一个线程请求方法时，会去检查锁状态。

如果锁状态是0，代表该锁没有被占用，使用CAS操作获取锁，将线程ID替换成自己的线程ID。
如果锁状态不是0，代表有线程在访问该方法。此时，如果线程ID是自己的线程ID，如果是可重入锁，会将status自增1，然后获取到该锁，进而执行相应的方法；如果是非重入锁，就会进入阻塞队列等待。
在释放锁时，

如果是可重入锁的，每一次退出方法，就会将status减1，直至status的值为0，最后释放该锁。
如果非可重入锁的，线程退出方法，直接就会释放该锁。
https://zhuanlan.zhihu.com/p/358828529
 *
 * */
/**
 * @author xin麒
 * @date 2023/8/20 19:09
 */
public class SingleSqlSessionUtil<T> {
//    AtomicBoolean flag = new AtomicBoolean(true);
    private volatile SqlSession sqlSession;
    private volatile T mapper;
    public SqlSession getSqlSessionWithNoAutoCommit() {
        if (sqlSession == null) {
            synchronized (this) {
                if (sqlSession == null) {
                    sqlSession = SqlSessionUtil.getSqlSessionWithNoAutoCommit();
                }
            }
        }
        return sqlSession;
    }

    public SqlSession getSqlSessionWithAutoCommit() {
        if (sqlSession == null) {
            synchronized (this) {
                if (sqlSession == null) {
                    sqlSession = SqlSessionUtil.getSqlSessionWithAutoCommit();
                }
            }
        }
        return sqlSession;
    }


    public T getMapper() {
        if (mapper == null) {
            synchronized (this) {
                if (mapper == null) {
                    mapper = getSqlSessionWithNoAutoCommit().getMapper(getTClass());
                }
            }
        }
        return mapper;
    }

    public T getMapperWithAutoCommit() {
        if (mapper == null) {
            synchronized (this) {
                if (mapper == null) {
                    mapper = getSqlSessionWithAutoCommit().getMapper(getTClass());
                }
            }
        }
        return mapper;
    }


    public Class<T> getTClass() {
        Class<T> tClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        return tClass;
    }

    public void closeSqlSession(){
        if (sqlSession != null) sqlSession.close();
    }
}
